let cssCache = {}
let cssParentCache = {}
let jsCache = {}
let imgTagName="image"
function genCssContent(block, unitRate, unitName, parentBlock) {
    let css = '';
    if(block.domType == 'img'&&block.style.backgroundImage){
        if (!block.props) block.props = {}
        block.props.src = block.style.backgroundImage.replace(/url\((.*)\)/, '$1')
        block.props.mode = 'aspectFill'
        delete block.style.backgroundImage
        delete block.style.backgroundSize
        delete block.style.backgroundRepeat
        delete block.style.backgroundPosition
    }
    for (let key in block.style) {
        let value = new String(block.style[key])
        // 处理RPX换算问题
        if (value) {
            let allCells = value.split(' ')
            for (let i = 0; i < allCells.length; i++) {
                if (allCells[i].match('[0-9]+px')) {
                    allCells[i] = (parseInt(allCells[i].replace('px', '')) * unitRate) + unitName
                }
            }
            value = allCells.join(' ')
        }
        let realCss = key.replace(/([A-Z])/g, "-$1").toLowerCase()
        // 过滤一些不需要的
        if (realCss == 'font-weight' && value == 'normal') continue
        if (realCss == 'font-style' && value == 'normal') continue
        // 过滤无子元素的样式
        if (!(block.blocks && (block.blocks.length > 0 || block.text != null))) {
            if (realCss == 'display' && value == 'flex') continue
            if (realCss == 'position' && value == 'relative') continue
            if (realCss == 'width' && value == '100%' && block.domType == 'div' && parentBlock != null &&
                parentBlock.blocks.length > 1) continue
            if (realCss == 'flex-direction') continue
            if (realCss == 'justify-content') continue
            if (realCss == 'align-items') continue
        }
        // 过滤Flex布局的默认值
        if (realCss == 'flex-direction' && value == 'row') continue
        if (realCss == 'justify-content' && value == 'flex-start') continue
        if (realCss == 'align-items' && value == 'flex-start') continue
        // 没有边框和padding就无需加上box-sizing
        if (!(block.style.border ||
            block.style.borderBottom ||
            block.style.borderLeft ||
            block.style.borderRight ||
            block.style.borderTop ||
            block.style.padding ||
            block.style.paddingTop ||
            block.style.paddingLeft ||
            block.style.paddingRight ||
            block.style.paddingBottom)) {
            if (realCss == 'box-sizing' && value == 'border-box') continue
        }
        if (realCss == 'border-top' && value == 'none') continue
        if (realCss == 'border-left' && value == 'none') continue
        if (realCss == 'border-right' && value == 'none') continue
        if (realCss == 'border-bottom' && value == 'none') continue
        if (realCss == 'border') {
            if (
                block.style.borderBottom == 'none' ||
                block.style.borderLeft == 'none' ||
                block.style.borderRight == 'none' ||
                block.style.borderTop == 'none'
            ) {
                continue
            }
        }
        if (value.indexOf('null') != -1) continue

        // 添加到结果中
        css += `\t\t${realCss}:${value};\n`
    }
    return css;
}

function genCssMapWithChildren(block, unitRate, unitName, parentBlock, xpath) {
    let result = xpath + "\n" + genCssContent(block, unitRate, unitName, parentBlock)
    for (let i in block.blocks) {
        result += `${xpath}>${i}\n`;
        result += genCssContent(block.blocks[i], unitRate, unitName, block, xpath + ">" + i)
    }
    return result
}

function handleCss(block, unitRate, unitName, parentBlock, css, cssName, parentName, parentCssPath, result) {
    // 样式
    css = genCssContent(block, unitRate, unitName, parentBlock);

    let cssMap = ''
    // css合并缓存
    if (css != '') {
        // 递归获取包括当前CSS和所有子CSS，构筑成Key
        cssMap = genCssMapWithChildren(block, unitRate, unitName, parentBlock, "self")
        if (cssCache[cssMap]&&cssParentCache[cssCache[cssMap]]&&cssParentCache[cssCache[cssMap]] == parentCssPath) {
            block.id = cssCache[cssMap]
            css = ''
        }
    }

    // 处理cssName
    cssName = block.id
    let currentCssPath = `.${block.id}`
    if (block.id.startsWith(parentName)) {
        cssName = block.id.substr(parentName.length + 1)
        currentCssPath = `${parentCssPath}>.${cssName}`
    }

    // 完成CSS的添加
    if (css != '') {
        result.css += `\t${currentCssPath}{\n` + css + `\t}`;
        if ((block.id.endsWith('-button') || block.id.endsWith('-btn'))) {
            result.css += `\n\t${currentCssPath}:hover{\n\t\topacity: 0.8;\n\t}`;
            result.css += `\n\t${currentCssPath}:active{\n\t\topacity: 0.5;\n\t}`;
        }
    }

    // 将CSS缓存起来，用来合并CSS
    if (css != '' && cssMap != '') {
        cssParentCache[block.id] = parentCssPath
        cssCache[cssMap] = block.id
    }
    return {css, cssName, currentCssPath};
}

/**
 * 转换为vue代码
 *    {
 *        // BLOCK对象
 *        block,
 *        defaultTag: 'view',
 *        stylesUnit: {
 *            name: 'rpx',
 *            rate: 2
 *        },
 *        clickEvent: 'tap'
 *    }
 */
let parse = (config) => {
    // 读取生成参数
    let {
        block,
        level,
        defaultTag,
        parentName,
        parentCssPath,
        clickEvent,
        parentBlock
    } = config;
    if (!config.stylesUnit) {
        config.stylesUnit = {
            name: 'px',
            rate: 1
        }
    }
    let unitName = config.stylesUnit.name
    let unitRate = config.stylesUnit.rate
    if (!level) {
        level = 1
    }

    if (level == 1) {
        cssCache = {}
        cssParentCache = {}
        jsCache = {}
        // 深拷贝
        block = JSON.parse(JSON.stringify(block))
    }
    let result = {
        html: '',
        css: '',
        js: ''
    }
    let html = ''

    let js = ''

    let {css, cssName, currentCssPath} =
        handleCss(block, unitRate, unitName, parentBlock, '', '', parentName, parentCssPath, result);
    /* 事件处理部分 */

    // 获取驼峰式Id
    let camelCaseId = block.id.toLowerCase().replace(/-(\w)/g, (match, p1) => p1.toUpperCase())

    // 处理按钮，先看CSS，如果CSS为空，那一定是不需要加事件
    if (css != '') {
        if ((block.id.endsWith('-button') || block.id.endsWith('-btn'))) {
            result.js +=
                `\t\t\t${camelCaseId}Click(){\n\t\t\t\tuni.showToast({\n\t\t\t\t\ttitle: '已触发${camelCaseId}Click事件',\n\t\t\t\t\ticon: 'none',\n\t\t\t\t\tduration: 2000\n\t\t\t\t})\n\t\t\t},`
        }
    }

    // 合并相似的事件
    if (result.js) {
        jsCache[block.id] = result.js
    }
    if (jsCache[block.id]) {
        js = jsCache[block.id]
    }

    /* DOM组件生成 */

    // 处理组件类型转换
    let targetDomType = block.domType
    if (block.domType) {
        if (block.domType == 'div') {
            targetDomType = defaultTag
        } else if (block.domType == 'img') {
            targetDomType = imgTagName
        } else {
            targetDomType = block.domType
        }
    } else {
        targetDomType = defaultTag
    }

    // 处理缩进
    for (let i = 0; i < level; i++) html += '\t'
    // 标签开始
    html +=
        `<${targetDomType} class="${cssName}"`
    if (block.props) {
        for (let i in block.props) {
            html += ` ${i}="${block.props[i]}"`
        }
    }
    if (js) html += ` @${clickEvent}="${camelCaseId}Click"`
    if (block.domType && block.domType == 'input' && block.text) html += ` value="${block.text}"`
    if (block.domType == 'input' || block.domType == 'img' || block.domType == imgTagName) {
        html += '/>'
    } else {
        html += '>'
    }
    // 内容
    if (block.text && (!block.domType || block.domType != 'input')) {
        if (block.blocks && block.blocks.length >= 1) {
            html += '\n'
            for (let i = 0; i < level + 1; i++) {
                html += '\t'
            }
        }
        html += block.text
    }
    if (block.blocks && block.blocks.length >= 1) {
        html += '\n'
        for (let i = 0; i < block.blocks.length; i++) {
            let child = block.blocks[i]
            let childHtml = parse({
                ...config,
                block: child,
                level: level + 1,
                parentName: block.id,
                parentCssPath: currentCssPath,
                parentBlock: block,
            })
            html += childHtml.html
            // 顺带处理CSS
            if (childHtml.css != '') {
                result.css += '\n' + childHtml.css
            }
            if (childHtml.js != '') {
                if (result.js == '') {
                    result.js = childHtml.js
                } else {
                    result.js += '\n' + childHtml.js
                }
            }
            if (i != block.blocks.length - 1) {
                html += '\n'
            }
        }
        html += '\n'
        for (let i = 0; i < level; i++) {
            html += '\t'
        }
    }

    if (!(block.domType == 'input' || block.domType == 'img' || block.domType == imgTagName)) {
        html += `</${targetDomType}>`
    }

    // 尾部
    if (block.id == 'root') {
        let outputFile = ""
        outputFile += `<template>\n${html}\n`
        outputFile += "</template>\n\n"
        outputFile += "<script>\n"
        outputFile += "\texport default {\n"
        outputFile += "\t\tdata: () => ({}),\n"
        outputFile += "\t\tprops:[],\n"
        outputFile += "\t\tmethods:{\n" + result.js + "\n\t\t},\n"
        outputFile += "\t\t// 组件生命周期钩子\n"
        outputFile += "\t\tbeforeCreate() {},\n"
        outputFile += "\t\tcreated() {},\n"
        outputFile += "\t\tbeforeMount() {},\n"
        outputFile += "\t\tmounted() {},\n"
        outputFile += "\t\tbeforeUpdate() {},\n"
        outputFile += "\t\tupdated() {},\n"
        outputFile += "\t\tbeforeDestroy() {},\n"
        outputFile += "\t\tdestroyed() {},\n"
        outputFile += "\t\t// Uniapp页面生命周期钩子\n"
        outputFile += "\t\tonPullDownRefresh() {\n\t\t\tuni.stopPullDownRefresh()\n\t\t},\n"
        outputFile += "\t\tonLoad(options) {},\n"
        outputFile += "\t\tonShow() {},\n"
        outputFile += "\t\tonReady() {},\n"
        outputFile += "\t\tonHide() {},\n"
        outputFile += "\t\tonUnload() {},\n"
        outputFile += "\t\tonBackPress() {},\n"
        outputFile += "\t\tonReachBottom() {},\n"
        outputFile += "\t\tonTabItemTap(index,pagePath,text) {},\n"
        outputFile += "\t\tonNavigationBarButtonTap(index) {},\n"
        outputFile += "\t}\n"
        outputFile += "</" + "script>\n\n"
        outputFile += "<style scoped>\n"
        outputFile += `\thtml,body,.root,uni-page-body,page #app{\n`
        outputFile += `\t\tpadding:0;\n`
        outputFile += `\t\tmargin:0;\n`
        outputFile += `\t\twidth:100%;\n`
        outputFile += `\t\theight:100%;\n`
        outputFile += `\t}\n`
        outputFile += result.css + "\n"
        outputFile += "</style>"
        html = outputFile
    }
    result.html = html
    return result
}
export default parse
